package com.qunar.homework2.service;

import com.google.common.io.Files;
import com.google.common.util.concurrent.*;
import com.qunar.homework2.task.ScrapyTask;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
//@Service
@Getter
@Setter
@NoArgsConstructor
public class ScrapyService<T>{

   // @Resource
    private final ListeningExecutorService listenableThreadPool;

    private final ConcurrentHashMap<T, Object> callbackResult;

    {
        listenableThreadPool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(100));
        callbackResult = new ConcurrentHashMap<>();
    }

    //baseUrl = https://api.douban.com/v2/book/
    public void ScrapyTInfo(List<String> idList, String baseUrl, String resultPath){
        if (idList == null || idList.size() == 0) {
            return;
        }

        try {
            CountDownLatch countDownLatch = new CountDownLatch(idList.size());

            final File resultFile = new File(resultPath);
            final FutureCallback<T> futureCallback = new FutureCallback<T>(){
                @Override
                public void onSuccess(@Nullable T t) {
                    callbackResult.put(t, null);
                    countDownLatch.countDown();
                    System.out.println("scrapy success:" + (countDownLatch.getCount()));
                }

                @Override
                public void onFailure(Throwable throwable) {
                    System.out.println("scrapy error:" + (countDownLatch.getCount()));

                    countDownLatch.countDown();
                }
            };
            ListenableFuture<T> listenableFuture;
            for (String id : idList){
                try {
                    listenableFuture = listenableThreadPool.submit(new ScrapyTask<T>(baseUrl + id));
                    Futures.addCallback(listenableFuture, futureCallback, listenableThreadPool);
                }catch (Exception e){
                    System.out.println("sleep error:");
                    e.printStackTrace();
                }
            }
            countDownLatch.await();
            StringBuilder sb = new StringBuilder();
            for (T item : callbackResult.keySet()){
                sb.append(item.toString()).append("\n");
            }
            Files.write(sb.toString().getBytes(), resultFile);
        }catch (Exception e){
            System.out.println("write result to file error:");
            e.printStackTrace();
        }
    }


    public void ScrapyBookInfoWithBlackList(List<String> idList, List<String> idBlackList, String baseUrl, String resultPath){

        final Set <String> idBlackSet = new HashSet<>(idBlackList);
        List<String> fiterIdList = new ArrayList<>();
        for (String id : idList){
            if (!idBlackList.contains(id)){
                fiterIdList.add(id);
            }
        }
        ScrapyTInfo(fiterIdList, baseUrl, resultPath);
    }
}
